home *** CD-ROM | disk | FTP | other *** search
- /*
- * node.c -- routines for node management
- */
-
- /* Copyright © 1986, 1988, 1989 1991 the Free Software Foundation, Inc.
- * This file is part of GAWK, the GNU implementation of the
- * AWK Progamming Language, modified for the Macintosh (also called hAWK).
- * GAWK is free software; you can redistribute or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 1, or any later version.
- * GAWK is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with GAWK; see the file "COPYING hAWK". If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * Slightly modified for THINK C 4 on the Macintosh by Ken Earle (Dynabyte) Aug 1991.
- */
- #include "AWK.H"
-
- /*extern double strtod();*/
-
- /*NODE.C*/
- AWKNUM r_force_number(NODE *n);
- NODE *r_force_string(NODE *s);
- NODE *dupnode(NODE *n);
- NODE *make_number(AWKNUM x);
- NODE *tmp_number(AWKNUM x);
- NODE *make_str_node(char *s, short len, short scan);
- static short group_tag_etc(char *p);
- NODE *tmp_string(char *s, short len);
- NODE *newnode(NODETYPE ty);
- void freenode(NODE *it);
- void do_deref(void);
-
- /*
- * We can't dereference a variable until after we've given it its new value.
- * This variable points to the value we have to free up
- */
- NODE *deref; /* inited in main */
-
- AWKNUM r_force_number(NODE *n)
- {
- char *ptr;
-
- #ifdef DEBUG
- if (n == NULL)
- cant_happen();
- if (n->type != Node_val)
- cant_happen();
- if(n->flags == 0)
- cant_happen();
- if (n->flags & NUM)
- return n->numbr;
- #endif
- if (n->stlen == 0)
- n->numbr = 0.0;
- else if (n->stlen == 1) {
- if (isdigit(n->stptr[0])) {
- n->numbr = n->stptr[0] - '0';
- n->flags |= NUMERIC;
- } else
- n->numbr = 0.0;
- } else {
- errno = 0;
- n->numbr = (AWKNUM) strtod(n->stptr, &ptr);
- /* the following >= should be ==, but for SunOS 3.5 strtod() */
- if (errno == 0 && ptr >= n->stptr + n->stlen)
- n->flags |= NUMERIC;
- }
- n->flags |= NUM;
- return n->numbr;
- }
-
- /*
- * the following lookup table is used as an optimization in force_string
- * (more complicated) variations on this theme didn't seem to pay off, but
- * systematic testing might be in order at some point
- */
- /* This way OK in an application...
- static char *values[] = {
- "0",
- "1",
- "2",
- "3",
- "4",
- "5",
- "6",
- "7",
- "8",
- "9"
- };
- */
- /* ..but in a THINK C code resource we need...*/
- static char *values[10];
- static void InitNumberValues(void);
- static void InitNumberValues()
- {
- values[0] = "0";
- values[1] = "1";
- values[2] = "2";
- values[3] = "3";
- values[4] = "4";
- values[5] = "5";
- values[6] = "6";
- values[7] = "7";
- values[8] = "8";
- values[9] = "9";
- }
-
- #define NVAL (sizeof(values)/sizeof(values[0]))
-
- NODE *r_force_string(NODE *s)
- {
- char buf[128];
- char *fmt;
- long num;
- char *sp = buf;
-
- #ifdef DEBUG
- if (s == NULL)
- cant_happen();
- if (s->type != Node_val)
- cant_happen();
- if (s->flags & STR)
- return s;
- if (!(s->flags & NUM))
- cant_happen();
- if (s->stref != 0)
- cant_happen();
- #endif
- s->flags |= STR;
- /* should check validity of user supplied OFMT */
- fmt = OFMT_node->var_value->stptr;
- if ((num = s->numbr) == s->numbr) {
- /* integral value */
- if (num < NVAL && num >= 0) {
- sp = values[num];
- s->stlen = 1;
- } else {
- (void) sprintf(sp, "%ld", num);
- s->stlen = strlen(sp);
- }
- } else {
- (void) sprintf(sp, fmt, s->numbr);
- s->stlen = strlen(sp);
- }
- s->stref = 1;
- emalloc(s->stptr, char *, s->stlen + 1, "force_string");
- memcpy(s->stptr, sp, s->stlen+1);
- return s;
- }
-
- /*
- * Duplicate a node. (For strings, "duplicate" means crank up the
- * reference count.)
- */
- NODE *dupnode(NODE *n)
- {
- register NODE *r;
-
- if (n->flags & TEMP) {
- n->flags &= ~TEMP;
- n->flags |= MALLOC;
- return n;
- }
- if ((n->flags & (MALLOC|STR)) == (MALLOC|STR)) {
- if (n->stref < 255)
- n->stref++;
- return n;
- }
- r = newnode(Node_illegal);
- *r = *n;
- r->flags &= ~(PERM|TEMP);
- r->flags |= MALLOC;
- if (n->type == Node_val && (n->flags & STR)) {
- r->stref = 1;
- emalloc(r->stptr, char *, r->stlen + 1, "dupnode");
- memcpy(r->stptr, n->stptr, r->stlen+1);
- }
- return r;
- }
-
- /* this allocates a node with defined numbr */
- NODE *make_number(AWKNUM x)
- {
- register NODE *r;
-
- r = newnode(Node_val);
- r->numbr = x;
- r->flags |= (NUM|NUMERIC);
- r->stref = 0;
- return r;
- }
-
- /*
- * This creates temporary nodes. They go away quite quickly, so don't use
- * them for anything important
- */
- NODE *tmp_number(AWKNUM x)
- {
- NODE *r;
-
- r = make_number(x);
- r->flags |= TEMP;
- return r;
- }
-
- /*
- * Make a string node.
- */
-
- NODE *make_str_node(char *s, short len, short scan)
- {
- register NODE *r;
- char *pf;
- register char *pt;
- register short c;
- register char *end;
-
- r = newnode(Node_val);
- emalloc(r->stptr, char *, len + 1, s);
- memcpy(r->stptr, s, len);
- r->stptr[len] = '\0';
- end = &(r->stptr[len]);
-
- if (scan) { /* scan for escape sequences */
- for (pf = pt = r->stptr; pf < end;) {
- c = *pf++;
- if (c == '\\' && !group_tag_etc(pf)) {
- c = parse_escape(&pf);
- if (c < 0)
- cant_happen();
- *pt++ = c;
- } else
- *pt++ = c;
- }
- len = pt - r->stptr;
- erealloc(r->stptr, char *, len + 1, "make_str_node");
- r->stptr[len] = '\0';
- r->flags |= PERM;
- }
- r->stlen = len;
- r->stref = 1;
- r->flags |= (STR|MALLOC);
-
- return r;
- }
-
- static short group_tag_etc(char *p)
- {
- char theChar = *p;
-
- if (theChar >= '1' && theChar <= '9' && !(*(p+1) >= '0' && *(p+1) <= '7'))
- return 1;
- /* special characters for regular expressions, which must have
- an escaping backslash before: w W < > b B
- */
- if (theChar == 'w' || theChar == 'W' || theChar == '<' || theChar == '>'
- || theChar == 'b' || theChar == 'B')
- return 1;
- return 0;
- }
-
- /* Read the warning under tmp_number */
- NODE *tmp_string(char *s, short len)
- {
- register NODE *r;
-
- r = make_string(s, len);
- r->flags |= TEMP;
- return r;
- }
-
-
- #define NODECHUNK 100
-
- static NODE *nextfree = NULL;
-
- NODE *newnode(NODETYPE ty)
- {
- NODE *it;
- NODE *np;
-
- #ifdef MPROF
- emalloc(it, NODE *, sizeof(NODE), "newnode");
- #else
- if (nextfree == NULL) {
- /* get more nodes and initialize list */
- emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "newnode");
- for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++)
- np->nextp = np + 1;
- np->nextp = NULL;
- }
- /* get head of freelist */
- it = nextfree;
- nextfree = nextfree->nextp;
- #endif
- it->type = ty;
- it->flags = MALLOC;
- #ifdef MEMDEBUG
- fprintf(stderr, "node: new: %0x\n", it);
- #endif
- return it;
- }
-
- void freenode(NODE *it)
- {
- #ifdef DEBUG
- NODE *nf;
- #endif
- #ifdef MEMDEBUG
- fprintf(stderr, "node: free: %0x\n", it);
- #endif
- #ifdef MPROF
- free((char *) it);
- #else
- #ifdef DEBUG
- for (nf = nextfree; nf; nf = nf->nextp)
- if (nf == it)
- fatal("attempt to free free node");
- #endif
- /* add it to head of freelist */
- it->nextp = nextfree;
- nextfree = it;
- #endif
- }
-
- #ifdef DEBUG
- pf()
- {
- NODE *nf = nextfree;
- while (nf != NULL) {
- fprintf(stderr, "%0x ", nf);
- nf = nf->nextp;
- }
- }
- #endif
-
- void do_deref()
- {
- if (deref == NULL)
- return;
- if (deref->flags & PERM) {
- deref = 0;
- return;
- }
- if ((deref->flags & MALLOC) || (deref->flags & TEMP)) {
- deref->flags &= ~TEMP;
- if (deref->flags & STR) {
- if (deref->stref > 1 && deref->stref != 255) {
- deref->stref--;
- deref = 0;
- return;
- }
- free(deref->stptr);
- }
- freenode(deref);
- }
- deref = 0;
- }
-
- void InitNode(void);
-
- void InitNode()
- {
- nextfree = NULL;
- if (!hAWKstackDepth)
- InitNumberValues();
- }
-
- void SaveNode(void);
- void RestoreNode(void);
- void SaveNode()
- {
- hs->nextfree = nextfree;
- }
-
- void RestoreNode()
- {
- nextfree = hs->nextfree;
- }
-